//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  Low level interfaces that allow separate components to use objects that are defined
//               in completely independant libraries so long as they satisfy the basic interface requirements.
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either express or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is MapWindow.dll
//
// The Initial Developer of this Original Code is Ted Dunsford. Created in August, 2007.
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

using MapWindow.Main;
using MapWindow.Geometries;

namespace MapWindow.Data
{
    /// <summary>
    /// Rather than being an uninstantiable base class, this is a "router" class that will
    /// make decisions based on the file extension or whatever being used and decide the best
    /// IFeatureLayer that matches the specifications.
    /// </summary>
    public class FeatureLayer: Object, IFeatureLayer
    {

        #region Variables

        /// <summary>
        /// A FeatureLayer stored internally that handles a specific file format
        /// </summary>
        protected IFeatureLayer _FeatureLayer; //  could be a ShapefileFeatureLayer for instance
        
        /// <summary>
        /// An envelope bounding the data elements on this layer
        /// </summary>
        protected IEnvelope _Envelope;

        #endregion

        #region Methods

        /// <summary>
        /// From a one layer at a time perspective, open a data source like a shapefile
        /// </summary>
        /// <param name="filename">The filename of the shapefile</param>
        public virtual void Open(string filename)
        {
            Open(filename, null);
        }

        /// <summary>
        /// From a one layer at a time perspective, open a data source like a shapefile
        /// </summary>
        /// <param name="filename">The filename of the shapefile</param>
        /// <param name="progHandler">An IProgress for showing the progress while loading the specified featurelayer</param>
        public virtual void Open(string filename, IProgHandler progHandler)
        {
            if (System.IO.Path.GetExtension(filename) != ".shp")
            {
                throw new NotSupportedException("Only .shp vector feature layers are currently supported.");
            }
            if (_FeatureLayer == null)
            {
                _FeatureLayer = new ShapefileFeatureLayer(filename, progHandler);
            }
        }



        #endregion

        /// <summary>
        /// Each layer can only have one type of geometry (Point, Line or Polygon).
        /// Attempting to add the wrong type of geometry once the type has been
        /// established will cause an error.  Adding the first geometry should
        /// automatically establish the type.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">"This feature layer is not empty and contains members of a different type.  You must clear the FeatureLayer before changing its geometry type.</exception>
        public FeatureTypes FeatureType
        {
            get { return _FeatureLayer.FeatureType; }
           
        }

        /// <summary>
        /// This doesn't do anything exactly because there is no file-specific information yet
        /// </summary>
        public FeatureLayer()
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="DataSource">A Data source... Not Implemented</param>
        public FeatureLayer(IFeatureDataSource DataSource)
        {
            // TO DO: figure out what kind of data source we have and do something
          
        }

        /// <summary>
        /// Not really implemented yet
        /// </summary>
        public IFeatureDataSource DataSource
        {
            get { return _FeatureLayer.DataSource; }
        }


        /// <summary>
        /// Probably will nix this as DataTables 
        /// </summary>
        public System.Data.DataTable DataTable
        {
            get { return _FeatureLayer.DataTable; }
        }

        /// <summary>
        /// Returns the bounding envelope in spatial coordinates for the entire layer
        /// TO DO: invalidate cached _Envelope when geometries change
        /// </summary>
        public IEnvelope Envelope
        {
            get
            {
                if (_Envelope == null)
                {
                    if (Features != null && Features.Count > 0)
                    {
                        _Envelope = new Envelope();
                        for (int shp = 0; shp < Features.Count; shp++)
                        {
                            _Envelope.ExpandToInclude(Features[shp].BasicGeometry.Envelope);

                        }
                    }

                }
                return _Envelope;
            }
        }

        /// <summary>
        /// A list of the features in this layer
        /// </summary>
        public List<IFeature> Features
        {
            get 
            {
                if (_FeatureLayer == null)return null;
                return _FeatureLayer.Features; 
            }
        }

        /// <summary>
        /// A list of the fields 
        /// </summary>
        public Dictionary<string, Field> Fields
        {
            get 
            {
                if (_FeatureLayer == null) return null;
                return _FeatureLayer.Fields;
            }
        }


        /// <summary>
        /// Many file formats do not permit multiple layers.  In such cases, no datasource
        /// is needed, and the feature layer can specify a filename to work with directly.
        /// Exceptions will be thrown if the filename specified is not one of the valid
        /// formats that supports single layer files.
        /// </summary>
        public string Filename
        {
            get { return _FeatureLayer.Filename; }
        }

        /// <summary>
        /// This is a clean identifier, rather than a full path name.
        /// </summary>
        public string Name
        {
            get
            {
                return _FeatureLayer.Name;
            }
            set
            {
                _FeatureLayer.Name = value;
            }
        }



        /// <summary>
        /// If this feature layer has a datasource, it will simply invoke the save method for that
        /// datasource.
        /// </summary>
        /// <exception cref="System.ApplicationException">The datasource or filename has not yet been specified for this layer.</exception>
        /// <exception cref="System.NotSupportedException">The specified extension is not currently supported.</exception>
        public virtual void Save()
        {
            if (Filename == null)
            {

                if (DataSource == null)
                {
                    throw new ApplicationException("The datasource or filename has not yet been specified for this layer.");
                }
                // A data source exists, so instruct it to save itself
                DataSource.Save();
            }
            else
            {
                if (_FeatureLayer != null)
                {
                    _FeatureLayer.Save();
                }
            }
        }

        /// <summary>
        /// Saves a datasource to the file.
        /// </summary>
        /// <param name="Filename">The string filename location to save to</param>
        /// <param name="Overwrite">Boolean, if this is true then it will overwrite a file of the existing name.</param>
        /// <exception cref="System.ApplicationException">A file of that name already exists and overwrite was set to false</exception>
        /// <exception cref="System.NotSupportedException">The specified extension is not currently supported.</exception>
        public virtual void SaveAs(string Filename, bool Overwrite)
        {
            // this will be replaced by more elaborate parsing to check data providers
            // and create an appropriate data source.
            if (System.IO.Path.GetExtension(Filename) != ".shp")
            {
                throw new NotSupportedException("The specified extension is not currently supported.");
            }

            // Since we aren't worried about database sources just yet
            if(Overwrite == false && System.IO.File.Exists(Filename))
            {
                throw new ApplicationException("A file of that name already exists and overwrite was set to false.");
            }

            if (System.IO.File.Exists(Filename))
            {
                Tools.DataManagement.Shapefile.Shapefile.Delete(Filename);
            }
            _FeatureLayer.SaveAs(Filename, true);
        }

        private void Save(string Filename)
        {
            if (System.IO.Path.GetExtension(Filename) != ".shp")
            {
                throw new NotSupportedException("Only .shp vector feature layers are currently supported.");
            }
            if (System.IO.File.Exists(Filename))
            {
                Tools.DataManagement.Shapefile.Shapefile.Delete(Filename);
            }
            if (_FeatureLayer != null)
            {
                _FeatureLayer.SaveAs(Filename, true);
            }
        }
    }
}
